/*
 * Copyright Konstantin Triger <kostat@gmail.com> 
 * 
 * This file is part of Jaque - JAva QUEry library <http://code.google.com/p/jaque/>.
 * 
 * Jaque is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Jaque is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package jaque.expressions;

import java.util.*;

import jaque.functions.*;
import static jaque.expressions.Expression.*;

final class QueryableExpressionVisitor extends SimpleExpressionVisitor {

	public static final QueryableExpressionVisitor Instance = new QueryableExpressionVisitor();

	private QueryableExpressionVisitor() {
	}

	public Expression visit(InvocationExpression e) {

		if (e.getMethod().getExpressionType() == ExpressionType.FieldAccess) {
			if (((MemberExpression) e.getMethod()).getMember().isSynthetic()) {
				Object value;
				try {
					value = e.apply(Interpreter.Instance).invoke(null);
				} catch (RuntimeException t) {
					throw t;
				} catch (Throwable t) {
					throw new RuntimeException(t);
				}

				if (value instanceof Function || value instanceof Function2)
					return quote(LambdaExpression.parse(value).apply(this));

				return constant(value, e.getResultType());
			}
		}

		List<Expression> args = e.getArguments();
		List<Expression> newArgs = new ArrayList<Expression>(args.size());
		for (int i = 0; i < args.size(); i++)
			newArgs.add(args.get(i).apply(this));

		return Expression.invoke((InvocableExpression) e.getMethod()
				.apply(this), Collections.unmodifiableList(newArgs));
	}

	public Expression visit(MemberExpression e) {
		Expression instance = e.getInstance();
		if (instance != null) {
			instance = stripQuotes(instance.apply(this));
			if (instance.getExpressionType() == ExpressionType.Lambda)
				return instance;
			if (instance != e.getInstance())
				return Expression.member(e.getExpressionType(), instance, e
						.getMember(), e.getResultType(), e.getParameters());
		}

		return e;
	}
}
